package org.lc.oauth.jackson;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.MissingNode;
import org.lc.oauth.vo.LcUserDetails;
import org.lc.platform.base.constant.AuthConstant;
import org.springframework.security.core.userdetails.User;
import com.fasterxml.jackson.databind.JsonDeserializer;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * Custom Deserializer for {@link User} class. This is already registered with
 * {@link SysUserMixin}. You can also use it directly with your mixin class.
 *
 * @author Jitendra Singh
 * @see SysUserMixin
 * @since 4.2
 */
class SysUserDeserializer extends JsonDeserializer<LcUserDetails> {

    private static final TypeReference<List<String>> LIST_TYPE = new TypeReference<>() {
    };

    /**
     * This method will create {@link User} object. It will ensure successful object
     * creation even if password key is null in serialized json, because credentials may
     * be removed from the {@link User} by invoking {@link User#eraseCredentials()}. In
     * that case there won't be any password key in serialized json.
     *
     * @param jp  the JsonParser
     * @param cxt the DeserializationContext
     * @return the user
     * @throws IOException if a exception during IO occurs
     */
    @Override
    public LcUserDetails deserialize(JsonParser jp, DeserializationContext cxt) throws IOException {
        ObjectMapper mapper = (ObjectMapper) jp.getCodec();
        JsonNode jsonNode = mapper.readTree(jp);
        List<String> roles = mapper.convertValue(jsonNode.get(AuthConstant.ROLES),
                LIST_TYPE);

        List<String> apis = mapper.convertValue(jsonNode.get(AuthConstant.APIS),
                LIST_TYPE);

        String clientId = readJsonNode(jsonNode, AuthConstant.CLIENTID).asText();
        String password = readJsonNode(jsonNode, AuthConstant.PASSWORD).asText();
        String userId = readJsonNode(jsonNode, AuthConstant.USER_ID).asText();
        String username = readJsonNode(jsonNode, AuthConstant.USER_NAME).asText();
        String nickName = readJsonNode(jsonNode, AuthConstant.NICK_NAME).asText();
        boolean superAdmin = readJsonNode(jsonNode, "superAdmin").asBoolean();
        return new LcUserDetails(clientId, userId, password, username, nickName, superAdmin, roles, new ArrayList<>(), apis);
    }

    private JsonNode readJsonNode(JsonNode jsonNode, String field) {
        return jsonNode.has(field) ? jsonNode.get(field) : MissingNode.getInstance();
    }

}
